Securing a Web Application with a Bluetooth Headset Adapter





0/5 (0 vote)
In this article, I am going to show you a proof-of-concept code segment that demonstrates of how you can use the serial number of a Bluetooth headset adapter to assist in providing an authentication mechanism to a web application.
Introduction
It is becoming more and more accepted that passwords alone are not enough to secure an application. There is a need for "two-factor authentication" to more adequately secure sensitive data. Two-factor authentication is the notion that in addition to a password, some physical identifier must be presented that assists in identifying a user to a system. Typical implementations of two-factor authentication feature a physical token or a phone-based app that generated a unique serial number every 60 seconds.
Fortunately, Plantronics new Legend UC headset adapter comes with a unique serial number that identifies it. With this additional piece of information, we can use this as part of this authentication mechanism. In this article, I am going to show you a proof-of-concept code segment that demonstrates of how you can use the serial number of a Bluetooth headset adapter to assist in providing an authentication mechanism to a web application. This is not a completely secure implementation, and there are ways to enhance the implementation, but I will leave those exercises to the security experts.
Project Setup
In this sample, I will start with an ASP.Net Empty Web Application. In order to use the Plantronics Spokes client-side library, we need to add jQuery to the application. I can add jQuery easily by running the following command in the package manager console:
Install-Package jQuery
With jQuery installed, I also need to add a reference to the spokes.js file. You can get a copy of this script in the Plantronics SDK ‘Zeus’ sample. If you installed the SDK, the spokes.js file is located at: C:\Program Files (x86)\Plantronics\Plantronics SDK\Samples\Zeus
I have assembled a very simple login box on a default.html file that looks like the following:
This simple box allows the user to key in their userid
,
password
, and their current authenticator value. In my hypothetical scenario,
we will automatically complete the authenticator box with the serial number
value from the headset. The HTML for this box looks like the following:
<fieldset id="loginBox">
<legend>Login:</legend>
<form method="post" action="/account/login.aspx">
<b>User Id:</b><input type="text" id="userId" name="userId" />
<br />
<b>Password:</b><input type="password" name="pass" />
<br />
<b>Authenticator:</b><input type="text" id="authenticator" name="authenticator" />
<br />
<input type="submit" value="Login" name="text" id="btnLogin" />
</form>
</fieldset>
Activating the Form
To activate the interaction with the Plantronics adapter, we need to start adding some JavaScript references and building a script to communicate with the headset services. First, I will add script references to the spokes.js and jquery.js files in this HTML file. Next, I will create and add a reference to a new script file called auth.js that will contain all of my logic to perform authentication.
Pro-tip: Create a reference at the top of any JavaScript file to allow Visual Studio 2010 and 2012 intellisense to identify the script content you are working with and present helpful tooltips to you while you code. Simply create a reference comment at the top of your file in the format:
/// <reference path="spokes.js" />
And Visual Studio make the references available to you.
For the purposes of this form, I am going to write a full JavaScript object that will maintain all information. I’ll start that construct with a self-executing anonymous function structure like the following:
/// <reference path="spokes.js" />
var auth = (function () {
})();
This will define a new object, remember that functions are objects in JavaScript, and assign it to the globally scoped auth variable. Inside of the function-object, I will define a constructor that will begin polling the adapter for information about the device and state changes.
var auth = (function () {
var pollingInterval = 5000;
var Auth = (function () {
var spokes = new Spokes("http://127.0.0.1:32001/Spokes");
var attached = false;
// Constructor
function Auth() {
ConnectSpokes();
setInterval(function () {
ConnectSpokes();
}, pollingInterval);
}
Auth.prototype.devicePresent = false;
Auth.prototype.serialNumber = "NOT SET";
return Auth;
})();
return new Auth();
})();
Several things are going on here: first, a private scope
variable called pollingInterval
is declared and is set with a 5000ms interval.
Next, an internal object is created with private scope variables for the Spokes
object and to also remember if we have properly connected to a device. Next a
constructor is defined that will attempt to connect to the adapter using the
Spokes (function to come) and then sets up a periodic poll to maintain that
connection.
It is important that we periodically poll for the state of the Spokes connection because the Spokes JavaScript library will not inform us if we are disconnected from the device. Instead, the library publishes events to an internal queue that we must poll. There is no way to see the current state of the adapter, you must remember what the last event raised was and behave accordingly. By taking these steps, we can automatically format and reformat the login box appropriately as the state of the device changes.
The ConnectSpokes
function that performs this polling makes
use of a call to the Spokes Device object. Here is the source for that function:
function ConnectSpokes () {
spokes.Device.deviceList(function (result) {
if (result.isError) {
console.log("Unable to connect to headset");
SetLoginBox(false);
}
else if (result.Result[0] == null) {
console.log("Error - Is there a headset connected?");
SetLoginBox(false);
}
else {
console.log("Connected to the headset adapter");
Auth.prototype.devicePresent = true;
Auth.prototype.serialNumber = result.Result[0].SerialNumber;
SetLoginBox(true)
}
});
};
The Spokes library exposes a deviceList
method that takes a
callback function to handle the results of the request to the hardware. This
callback is executed asynchronously, so the ConnectSpokes
function actually and
returns control very quickly, but is not completed executing until some time
later. The result object that is passed in to this method is inspected to
determine if there are any errors in connecting to the adapter, and to log
appropriate messages to the console. You could easily change this to perform
some other action if necessary, in this sample I have it call setLoginBox
with
a false argument. If we do have a successful connection to the device, I log
it appropriately and set two static methods on the Auth
object using the
Auth.prototype
syntax. These two variables indicate that there is a
devicePresent
and the serial number of the device. Finally, in the case that
we did connect properly to the headset adapter, I call SetLoginBox
with a true
argument.
The SetLoginBox
function is an internal function that uses
some jQuery DOM manipulation to configure the authenticator box and to
intercept the login button’s click action to set the authenticator value from
the serial number on the headset adapter:
function SetLoginBox(headsetPresent) {
if ($("#loginBox")[0]) {
if (headsetPresent) {
if (!attached) {
$("#authenticator").attr("disabled", true).css({ backgroundColor: "silver", color: "red", fontWeight: "bold", textAlign: "center" }).val("HEADSET");
$("#btnLogin").click(function () {
$("FORM").append("<input type='hidden' value='" + auth.serialNumber + "' name='authenticator'/>");
})
attached = true
}
} else {
if (attached) {
$("#authenticator").removeAttr("disabled").css({ backgroundColor: "transparent", color: "inherit", fontWeight: "inherit", textAlign: "inherit" }).val("");
$("#btnLogin").unbind("click");
attached = false;
}
}
}
};
I wrap the execution of this method in a test for the
loginBox
object. By taking this defensive coding step, I can add this code to
any page on the application that the loginBox
may appear on. Finally, I needed
to wrap the checks and formatting for the HTML objects in a check on the class
scoped attached variable. Without this check, this method would attach
multiple click event handlers to the btnLogin
object. This would create a
nasty memory leak if this method had executed hundreds of times, and had
hundreds of handlers hooked up to the click of the login button.
The resulting format of this method when the headset adapter is present looks like the following figure:
This is a simple implementation, but the concepts are sound: you can use a bluetooth device to provide authenticator capabilities.
Download the source code for this article and the Plantronics SDK to give it a try. I’m sure you’ll find some great capabilities that you can use in your applications